/*
 * @Author: 缄默
 * @Date: 2021-12-12 15:18:53
 * @LastEditors: 缄默
 * @LastEditTime: 2021-12-27 16:50:36
 */

//访问者模式

//该实现可以类比为超市结账
//购物车就是对象结构角色
//购买者（一个具体的访问者）需要知道所购买商品的总价
//而超市采购（另一个具体访问者）需要知道各种商品（不同种类的element）购买了多少个以补充
//二者都不能污染元素，且两种访问者对同一个对象结构实施不同的角色
#include <iostream>
#include <vector>

using namespace std;

class Visitor;

class Element { 
public:
    virtual ~Element() { }
    virtual void Accept(Visitor* vis) = 0;
};

class Visitor {
public:
    virtual ~Visitor() { }

    virtual void VisitConcreteElementA(Element* elm) = 0;
    virtual void VisitConcreteElementB(Element* elm) = 0;
protected:
    Visitor() { };
};


class ConcreteElementA : public Element{ 
public: 
    void Accept(Visitor* vis) {
        vis->VisitConcreteElementA(this);
        cout << "visiting ConcreteElementA..." << endl;
    }
};

class ConcreteElementB : public Element{ 
public: 
    void Accept(Visitor* vis) {
        vis->VisitConcreteElementB(this);
        cout << "visiting ConcreteElementB..." << endl;
    }
};



class ConcreteVisitorA :public Visitor {
public:
    void VisitConcreteElementA(Element* elm) {
        //element方法
        cout << "ConcreteVisitorA VisitConcreteElementA..." << endl;
    }
    void VisitConcreteElementB(Element* elm) {
        cout << "ConcreteVisitorA VisitConcreteElementB..." << endl;
    }
};

class ConcreteVisitorB : public Visitor {
public:
    void VisitConcreteElementA(Element* elm) {
        cout << "ConcreteVisitorB VisitConcreteElementA..." << endl;
    }
    void VisitConcreteElementB(Element* elm) {
        cout << "ConcreteVisitorB VisitConcreteElementB..." << endl;
    }
};

class ObjectStructure {
private:
    vector<Element*> _vectorEle;
public:
    void addElement(Element* ele) {
        _vectorEle.push_back(ele);
    }

    void removeElement(Element* ele) {
        //删除元素ele
    }

    void Accept(Visitor* vis) {
        for (auto ele : _vectorEle) {
            ele->Accept(vis);
        }
    }
};

int main() {
    //这里可以采用工厂模式初始化元素

    Element* eleA = new ConcreteElementA();
    Element* eleB = new ConcreteElementB();
    ObjectStructure* obj = new ObjectStructure();
    obj->addElement(eleA);
    obj->addElement(eleB);

    Visitor* visA = new ConcreteVisitorA();
    Visitor* visB = new ConcreteVisitorB();

    //类似于策略模式 不同的访问者（对象结构的处理方法）对应着不同的策略
    obj->Accept(visA);
    cout << endl;

    obj->Accept(visB);

    delete eleA;
    delete eleB;
    delete obj;
    delete visA;
    delete visB;
    return 0;

}